昨天聊了模型架構跟金鑰儲存。今天要往上一層,看請求真正送進來的地方——Gateway,還有讓系統不會因為一個模型掛掉就整個失敗的機制:Fallback。
Gateway 是這個系統對外的統一入口。不管是 Cursor、自己寫的程式,還是其他工具,只要把呼叫模型的請求送到這個入口就好,格式是 OpenAI-compatible 的 /v1/chat/completions——也就是說,只要把原本呼叫 OpenAI 的程式碼改一下 baseURL,指向這個 Router,就能直接用,不用學一套新的呼叫方式。
Fallback 則是當一個 model 名稱底下掛了好幾筆 Deployment(依 Priority 排序)時,Gateway 會依序嘗試:先試優先度最高的那一筆,如果失敗(逾時、上游回傳錯誤等),自動改試下一筆,直到成功或全部候選都試過為止。呼叫端完全不需要自己處理重試邏輯,這一切都在 Gateway 內部完成。
Gateway 選擇做成 OpenAI-compatible 格式,理由很直接:OpenAI 是目前普及度最高、大家都熟悉的格式,筆者一開始接觸 LLM API 用的也是這個格式,而且多數模型服務都會提供 OpenAI 相容的介面——選這個格式,等於一開始就站在相容性最廣的那一邊。
Fallback 是一開始規劃時就決定要做的功能。中間確實猶豫過一次:曾經想過個人版的使用者不太可能有資源去部署好幾份「同一個模型」當備援,一度想把這個功能拿掉。但後來想通了——Fallback 不需要侷限在「同一個模型的多個副本」,也可以拿來支援「不同模型互相接手」。舉例來說,一個應用原本用模型 A,A 失效時想改用模型 B 頂上,只要在 Gateway 這邊把兩者取同一個對外名稱,就能讓不同模型之間也享有自動切換的效果——這才是讓 Fallback 留下來的關鍵理由。
全部候選都失敗時,會把最後一筆候選的失敗原因回傳給使用者,這是一開始就定好的規則。但上線一陣子之後,發現一個沒設計滿的地方:不管是「這個名稱本來就只掛了一個 model、它失敗了」,還是「整條備援鏈全部都試過還是失敗」,呼叫端拿到的都是同一種錯誤,沒辦法分辨這兩種嚴重程度完全不同的情況——後者代表連備援都救不回來,理論上更該被當一回事。
修法不是去找新的資料,而是把本來就有在記錄的「試了幾次」這個數字,多做一層轉換:只要候補鏈真的用盡了,回應跟紀錄裡就會多標一個明確的訊號,讓使用者一看就知道「這次連備援都救不回來」,不用自己回頭比對嘗試次數才能推斷。不過目前受限於「一個請求對應一筆紀錄」的設計,還是只保留最後一筆候選的失敗原因,沒辦法完整記錄下每一筆候選各自為什麼失敗——這個取捨目前先接受,之後真的需要更細的診斷資訊時再回來加。
Gateway 提供一個大家都熟悉、改個 baseURL 就能用的統一入口;Fallback 則是把「同一個名稱底下可以掛多筆候選」這個架構,從「同模型備援」延伸成「跨模型互相支援」,讓容錯設計的彈性比原本設想的更大。
明天會分享模型健康檢測——如何確定自己設定的模型真的可以穩定連線?
如果大家看到這邊對這個專案有興趣,完整程式碼都已經整理並開源在 GitHub 上:
👉 GitHub Repo